﻿using Microsoft.AspNetCore.Authorization;
using PHMEE.Entities.BaseInfo.Units;
using PHMEE.Managers.BaseInfo.Points;
using PHMEE.ToolKits;
using System.ComponentModel;
using System.Globalization;
using System.Linq.Dynamic.Core;
using System.Xml.Linq;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Uow;
using static PHMEE.PHMEEAdminPermissions;

namespace PHMEE.Admin
{

    public class VesselAppService : PHMEEAdminAppService, IVesselAppService
    {
        private readonly IVesselManager vesselManager;
        private readonly IVesselRepository vesselRepository;

        public VesselAppService(IVesselManager vesselManager, IVesselRepository vesselRepository)
        {
            this.vesselManager = vesselManager;
            this.vesselRepository = vesselRepository;
        }

        #region 船舶

        [Authorize(PHMEEAdminPermissions.Vessels.Create)]
        public async Task<Guid> CreateVesselAsync(VesselCreateDto input)
        {
            var vessel = await vesselManager.CreateVessel(input.Type, input.FleetId, input.Name, input.NameEn, input.IMO);

            vessel.Tags = input.Tags;

            vessel.CallSign = input.CallSign;

            vessel.FlagState = input.FlagState;

            vessel.GrossTon = input.GrossTon;

            vessel.DeadWeightTon = input.DeadWeightTon;

            vessel.NetTon = input.NetTon;

            vessel.EEXI = input.EEXI;

            vessel.EEDI = input.EEDI;

            vessel.ClassificationSociety = input.ClassificationSociety;

            vessel.FlowMeterMode = input.FlowMeterMode;

            vessel.Type = input.Type;

            vessel.SerializeProperties(input.DerivedPropertiesJson);

            await vesselRepository.PhmeeCreate(vessel);

            return vessel.Id;
        }

        [Authorize(PHMEEAdminPermissions.Vessels.Update)]
        public async Task UpdateVesselAsync(VesselUpdateDto input)
        {
            var query = await vesselRepository.PhmeeGetQuery();

            var (expression, localizedName) = vesselManager.GetVesselExpression(input.Name, input.NameEn, input.FleetId);

            if (query.Where(expression).Any(item => item.Id != input.Id))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.VesselNameAlreadyExist], PHMEEDomainErrorCodes.VesselNameAlreadyExist).WithData("Name", localizedName);
            }

            var vessel = await vesselRepository.PhmeeGetById(input.Id);

            // 其他属性赋值
            vessel.SetName(input.Name);

            vessel.SetNameEn(input.NameEn);

            vessel.SetImo(input.IMO);

            vessel.Tags = input.Tags;

            vessel.CallSign = input.CallSign;

            vessel.FlagState = input.FlagState;

            vessel.GrossTon = input.GrossTon;

            vessel.DeadWeightTon = input.DeadWeightTon;

            vessel.NetTon = input.NetTon;

            vessel.EEXI = input.EEXI;

            vessel.EEDI = input.EEDI;

            vessel.ClassificationSociety = input.ClassificationSociety;

            vessel.FlowMeterMode = input.FlowMeterMode;

            vessel.SerializeProperties(input.DerivedPropertiesJson);

            await vesselRepository.PhmeeUpdate(vessel);
        }

        [Authorize(PHMEEAdminPermissions.Vessels.Delete)]
        public async Task DeleteVesselAsync(Guid id)
        {
            await vesselRepository.PhmeeDelete(id);
        }

        [Authorize(PHMEEAdminPermissions.Vessels.Default)]
        public async Task<PagedResultDto<VesselDto>> GetPagedVesselsAsync(VesselListDto input)
        {
            var query = await vesselRepository.PhmeeGetQuery();

            query = query.WhereIf(input.FleetId != null, item => item.FleetId == input.FleetId);

            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Name.Contains(input.Name) || item.NameEn.Contains(input.Name));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderByDescending(item => item.CreationTime);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var vessels = await AsyncExecuter.ToListAsync(query);

            var items = ObjectMapper.Map<List<Vessel>, List<VesselDto>>(vessels);

            return new PagedResultDto<VesselDto>(totalCount, items);
        }

        [Authorize(PHMEEAdminPermissions.Vessels.Default)]
        public async Task<VesselDto> GetVesselByIdAsync(Guid id)
        {
            var vessel = await vesselRepository.PhmeeGetById(id);

            var vesselDto = ObjectMapper.Map<Vessel, VesselDto>(vessel);

            return vesselDto;
        }

        public List<OperationOptionInt> GetVesselTypes(Guid? id)
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedVessel}";

            var options = vesselManager.GetVesselTypes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public List<OperationOptionInt> GetVesselFlowMeterModes(Guid? id)
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedVesselFlowmetorMode}";

            var options = vesselManager.GetVesselFlowMeterModes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        [Authorize(PHMEEAdminPermissions.Vessels.Create)]
        public async Task<List<VesselBatchTree>> GetVesselUnitInitialRows(List<Guid> vesselIds)
        {
            List<VesselBatchTree> list = new List<VesselBatchTree>();

            var query = await vesselRepository.PhmeeGetQuery();

            query = query.WhereIf(vesselIds != null, item => vesselIds.Contains(item.Id));

            var vessels = await AsyncExecuter.ToListAsync(query);

            foreach (var vessel in vessels)
            {
                var model = new VesselBatchTree();

                model.Id = vessel.Id;

                model.DisplayName = vessel.DisplayName;

                model.Name = vessel.Name;

                model.NameEn = vessel.NameEn;

                model.TypeEnumInt = (int)vessel.Type;

                model.Properties = new LevelProperties()
                {
                    VesselId = vessel.Id,
                };

                foreach (var unitType in vessel.GetUnitTypeOptions())
                {
                    var children = new VesselBatchTree();

                    var id = GuidGenerator.Create();

                    var localizedName = $"UnitEnum";

                    var nameEn = PHMEECoreHelper.PhmeeGetDescription(unitType);

                    var displayName = L[$"{localizedName}:{nameEn}"];

                    children.Id = id;

                    children.DisplayName = displayName;

                    children.NameEn = nameEn;

                    children.TypeEnumInt = (int)unitType;

                    children.Properties = new LevelProperties()
                    {
                        VesselId = vessel.Id,
                    };

                    model.Children.Add(children);
                }

                list.Add(model);

            }

            return list;

        }

        [Authorize(PHMEEAdminPermissions.Vessels.Create)]
        [UnitOfWork]
        public async Task BatchVesselUnitRows(List<VesselBatchTree> rows)
        {
            var dict = rows.Where(item => item.Properties.VesselId != null && item.IsActive).GroupBy(item => item.Properties.VesselId).ToDictionary(group => group.Key, group => group.ToList());

            var query = await vesselRepository.WithDetailsAsync();

            query = query.Where(item => dict.Keys.Contains(item.Id));

            var vessels = await AsyncExecuter.ToListAsync(query);

            foreach (var entry in dict)
            {
                var vessel = vessels.FirstOrDefault(item => item.Id == entry.Key);

                if (vessel != null)
                {
                    foreach (var row in entry.Value)
                    {
                        var unitType = (UnitEnum)row.TypeEnumInt;

                        var maxNumber = vessel.Units.Where(item => item.Type == unitType).Select(item => item.Number).OrderByDescending(number => number).FirstOrDefault();

                        Action<Unit> action = item =>
                        {
                            item.Type = unitType;

                            item.SerializeProperties(item.InitDefaultProperties());
                        };
                        for (var i = 1; i <= row.Numbers; i++)
                        {
                            var number = i + maxNumber;

                            var unitId = GuidGenerator.Create();

                            var name = $"{number}# {row.Name}";

                            var nameEn = $"{number}# {row.NameEn}";

                            vessel.AddUnit(vessel.Id, unitId, name, nameEn, number, unitType, action, L);
                        }
                    }

                    await vesselRepository.PhmeeUpdate(vessel);
                }
            }

        }


        #endregion

        #region 机组

        [Authorize(PHMEEAdminPermissions.Units.Create)]
        public async Task<Guid> CreateUnitAsync(UnitCreateDto input)
        {
            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Unit> action = item =>
            {
                item.Tags = input.Tags;

                item.Area = input.Area;

                item.Type = input.Type;

                item.Threshold = input.Threshold;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            Guid unitId = GuidGenerator.Create();

            vessel.AddUnit(input.VesselId, unitId, input.Name, input.NameEn, input.Number, input.Type, action, L);

            await vesselRepository.PhmeeUpdate(vessel);

            return unitId;
        }

        [Authorize(PHMEEAdminPermissions.Units.Update)]
        public async Task UpdateUnitAsync(UnitUpdateDto input)
        {
            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Unit> action = item =>
            {
                item.SetName(input.Name);

                item.SetNameEn(input.NameEn);

                item.Tags = input.Tags;

                item.Area = input.Area;

                item.Threshold = input.Threshold;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            vessel.UpdateUnit(input.Id, input.Name, input.NameEn, action, L);
        }

        [Authorize(PHMEEAdminPermissions.Units.Delete)]
        public async Task DeleteUnitAsync(Guid id, Guid vesselId)
        {
            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            vessel.RemoveUnit(id, L);

            await vesselRepository.PhmeeUpdate(vessel);
        }

        [Authorize(PHMEEAdminPermissions.Units.Default)]
        public async Task<UnitDto> GetUnitByIdAsync(Guid id, Guid vesselId)
        {
            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            var unit = vessel.GetUnit(id, L);

            var unitDto = new UnitDto
            {
                Id = unit.Id,
                Name = unit.Name,
                NameEn = unit.NameEn,
                DisplayName = unit.DisplayName,
                Number = unit.Number,
                Tags = unit.Tags,
                Area = unit.Area,
                Threshold = unit.Threshold,
                Type = unit.Type,
                DerivedPropertiesJson = unit.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(vessel),
            };

            return unitDto;
        }

        [Authorize(PHMEEAdminPermissions.Units.Default)]
        public async Task<PagedResultDto<UnitDto>> GetPagedUnitsAsync(UnitListDto input)
        {

            var queryVessel = await vesselRepository.PhmeeGetQuery();

            var query = queryVessel.SelectMany(item => item.Units
                                   .Select(unit => new { Unit = unit, Vessel = item }));

            query = query.WhereIf(input.VesselId != null, item => item.Vessel.Id == input.VesselId);

            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Unit.Name.Contains(input.Name) || item.Unit.NameEn.Contains(input.Name));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderBy(item => item.Unit.VesselId).ThenBy(item => item.Unit.Type).ThenBy(item => item.Unit.Number);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var units = await AsyncExecuter.ToListAsync(query);

            var items = units.Select(u => new UnitDto
            {
                Id = u.Unit.Id,
                Name = u.Unit.Name,
                NameEn = u.Unit.NameEn,
                DisplayName = u.Unit.DisplayName,
                Number = u.Unit.Number,
                Tags = u.Unit.Tags,
                Area = u.Unit.Area,
                Type = u.Unit.Type,
                Threshold = u.Unit.Threshold,
                DerivedPropertiesJson = u.Unit.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(u.Vessel),
                VesselDisplayName = u.Vessel.DisplayName
            }).ToList();

            return new PagedResultDto<UnitDto>(totalCount, items);


        }

        public List<OperationOptionInt> GetUnitTypes(Guid? id)
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedUnit}";

            var options = vesselManager.GetUnitTypes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public Dictionary<string, object> GetUnitInitDefaultProperties(UnitEnum type)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>();

            Guid id = GuidGenerator.Create();

            switch (type)
            {
                case UnitEnum.BallastPumpUnit:
                    dict = new BallastPumpUnit(id, id, "BallastPumpUnit", "BallastPumpUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.CombustionAirBlowerUnit:
                    dict = new CombustionAirBlowerUnit(id, id, "CombustionAirBlowerUnit", "CombustionAirBlowerUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.FuelOilSeparatorUnit:
                    dict = new FuelOilSeparatorUnit(id, id, "FuelOilSeparatorUnit", "FuelOilSeparatorUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.LubricatingOilPumpUnit:
                    dict = new LubricatingOilPumpUnit(id, id, "LubricatingOilPumpUnit", "LubricatingOilPumpUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.LubricatingOilSepaUnit:
                    dict = new LubricatingOilSepaUnit(id, id, "LubricatingOilSepaUnit", "LubricatingOilSepaUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.MainEngineUnit:
                    dict = new MainEngineUnit(id, id, "MainEngineUnit", "MainEngineUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.MainGeneratorUnit:
                    dict = new MainGeneratorUnit(id, id, "MainGeneratorUnit", "MainGeneratorUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.SeaWaterPumpUnit:
                    dict = new SeaWaterPumpUnit(id, id, "SeaWaterPumpUnit", "SeaWaterPumpUnit", 1).InitDefaultProperties();
                    break;
                case UnitEnum.StartingAirCompressUnit:
                    dict = new StartingAirCompressUnit(id, id, "StartingAirCompressUnit", "StartingAirCompressUnit", 1).InitDefaultProperties();
                    break;
            }

            return dict;
        }

        #endregion

        #region 设备

        [Authorize(PHMEEAdminPermissions.Equipments.Create)]
        public async Task<Guid> CreateEquipmentAsync(EquipmentCreateDto input)
        {

            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Equipment> action = item =>
            {
                item.Tags = input.Tags;

                item.Model = input.Model;

                item.Manufacturer = input.Manufacturer;

                if (DateTime.TryParse(input.ManufacturerTime, out DateTime manufacturerTime))
                {
                    item.ManufacturerTime = manufacturerTime;
                }

                item.RatedSpeed = input.RatedSpeed;

                item.RatedPower = input.RatedPower;

                item.Type = input.Type;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            Guid equipmentId = GuidGenerator.Create();

            vessel.AddEquipment(input.UnitId, equipmentId, input.Name, input.NameEn, input.Number, input.Type, action, L);

            await vesselRepository.PhmeeUpdate(vessel);

            return equipmentId;

        }

        [Authorize(PHMEEAdminPermissions.Equipments.Default)]
        public async Task UpdateEquipmentAsync(EquipmentUpdateDto input)
        {

            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Equipment> action = item =>
            {
                item.SetName(input.Name);

                item.SetNameEn(input.NameEn);

                item.Tags = input.Tags;

                item.Model = input.Model;

                item.Manufacturer = input.Manufacturer;

                if (DateTime.TryParse(input.ManufacturerTime, out DateTime manufacturerTime))
                {
                    item.ManufacturerTime = manufacturerTime;
                }
                else
                {
                    item.ManufacturerTime = null;
                }

                item.RatedSpeed = input.RatedSpeed;

                item.RatedPower = input.RatedPower;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            vessel.UpdateEquipment(input.UnitId, input.Id, input.Name, input.NameEn, action, L);

            await vesselRepository.PhmeeUpdate(vessel);


        }

        [Authorize(PHMEEAdminPermissions.Equipments.Delete)]
        public async Task DeleteEquipmentAsync(Guid id, Guid vesselId, Guid unitId)
        {
            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            vessel.RemoveEquipment(unitId, id, L);

            await vesselRepository.PhmeeUpdate(vessel);


        }

        [Authorize(PHMEEAdminPermissions.Equipments.Default)]
        public async Task<EquipmentDto> GetEquipmentByIdAsync(Guid id, Guid vesselId, Guid unitId)
        {

            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            var unit = vessel.GetUnit(unitId, L);

            var equipment = vessel.GetEquipment(unitId, id, L);

            var equipmentDto = new EquipmentDto
            {
                Id = equipment.Id,
                Name = equipment.Name,
                NameEn = equipment.NameEn,
                Number = equipment.Number,
                Tags = equipment.Tags,
                Model = equipment.Model,
                Manufacturer = equipment.Manufacturer,
                ManufacturerTime = equipment.ManufacturerTime?.PhmeeToFriendlyDateTimeString(),
                RatedSpeed = equipment.RatedSpeed,
                RatedPower = equipment.RatedPower,
                Type = equipment.Type,
                DerivedPropertiesJson = equipment.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(vessel),
                Unit = ObjectMapper.Map<Unit, UnitDto>(unit),
            };

            return equipmentDto;

        }

        [Authorize(PHMEEAdminPermissions.Equipments.Default)]
        public async Task<PagedResultDto<EquipmentDto>> GetPagedEquipmentsAsync(EquipmentListDto input)
        {

            var queryVessel = await vesselRepository.PhmeeGetQuery();

            var query = queryVessel.SelectMany(vessel => vessel.Units.SelectMany(unit => unit.Equipments
                                                                     .Select(equipment => new { Vessel = vessel, Unit = unit, Equipment = equipment })));

            query = query.WhereIf(input.UnitId != null, item => item.Unit.Id == input.UnitId);

            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Equipment.Name.Contains(input.Name) || item.Equipment.NameEn.Contains(input.Name));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderBy(item => item.Equipment.UnitId).ThenBy(item => item.Equipment.Type).ThenBy(item => item.Equipment.Number);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var equipments = await AsyncExecuter.ToListAsync(query);

            var items = equipments.Select(e => new EquipmentDto
            {
                Id = e.Equipment.Id,
                Name = e.Equipment.Name,
                NameEn = e.Equipment.NameEn,
                DisplayName = e.Equipment.DisplayName,
                Number = e.Equipment.Number,
                Tags = e.Equipment.Tags,
                Model = e.Equipment.Model,
                Manufacturer = e.Equipment.Manufacturer,
                ManufacturerTime = e.Equipment.ManufacturerTime?.PhmeeToFriendlyDateTimeString(),
                DerivedPropertiesJson = e.Equipment.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(e.Vessel),
                VesselDisplayName = e.Vessel.DisplayName,
                Unit = ObjectMapper.Map<Unit, UnitDto>(e.Unit),
                UnitDisplayName = e.Unit.DisplayName
            }).ToList();

            return new PagedResultDto<EquipmentDto>(totalCount, items);


        }

        public async Task<List<OperationOptionInt>> GetEquipmentTypes(Guid? id, Guid vesselId, Guid unitId)
        {
            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            var unit = vessel.GetUnit(unitId, L);

            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedEquipment}";

            var options = vesselManager.GetEquipmentTypes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            options = options.Where(item => unit.GetEquipmentTypeOptions().Contains((EquipmentEnum)item.Key)).ToList();

            return options;

        }

        public List<OperationOptionInt> GetEquipmentRotationModes()
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedEquipmentRotationMode}";

            var options = vesselManager.GetEquipmentRotationModes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public List<OperationOptionInt> GetEquipmentConnectModes()
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedEquipmentConnectMode}";

            var options = vesselManager.GetEquipmentConnectModes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public List<OperationOptionInt> GetEquipmentSupportFlexibilityModes()
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedEquipmentSupportFlexibilityMode}";

            var options = vesselManager.GetEquipmentSupportFlexibilityModes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public List<OperationOptionInt> GetEquipmentBearingTypes()
        {
            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedEquipmentBearingType}";

            var options = vesselManager.GetEquipmentBearingTypes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        #endregion

        #region 部件

        [Authorize(PHMEEAdminPermissions.Components.Create)]
        public async Task<Guid> CreateComponentAsync(ComponentCreateDto input)
        {

            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Component> action = item =>
            {
                item.Tags = input.Tags;

                item.Model = input.Model;

                item.Type = input.Type;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            Guid componentId = GuidGenerator.Create();

            vessel.AddComponent(input.UnitId, input.EquipmentId, componentId, input.Name, input.NameEn, input.Number, input.Type, action, L);

            await vesselRepository.PhmeeUpdate(vessel);

            return componentId;

        }

        [Authorize(PHMEEAdminPermissions.Components.Default)]
        public async Task UpdateComponentAsync(ComponentUpdateDto input)
        {

            var vessel = await vesselRepository.PhmeeGetById(input.VesselId);

            Action<Component> action = item =>
            {
                item.SetName(input.Name);

                item.SetNameEn(input.NameEn);

                item.Tags = input.Tags;

                item.Model = input.Model;

                item.SerializeProperties(input.DerivedPropertiesJson);
            };

            vessel.UpdateComponent(input.UnitId, input.EquipmentId, input.Id, input.Name, input.NameEn, action, L);

            await vesselRepository.PhmeeUpdate(vessel);

        }

        [Authorize(PHMEEAdminPermissions.Components.Delete)]
        public async Task DeleteComponentAsync(Guid id, Guid vesselId, Guid unitId, Guid equipmentId)
        {

            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            vessel.RemoveComponent(unitId, equipmentId, id, L);

            await vesselRepository.PhmeeUpdate(vessel);


        }

        [Authorize(PHMEEAdminPermissions.Components.Default)]
        public async Task<ComponentDto> GetComponentByIdAsync(Guid id, Guid vesselId, Guid unitId, Guid equipmentId)
        {

            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            var unit = vessel.GetUnit(unitId, L);

            var equipment = vessel.GetEquipment(unitId, equipmentId, L);

            var component = vessel.GetComponent(unitId, equipmentId, id, L);

            var componentDto = new ComponentDto
            {
                Id = component.Id,
                Name = component.Name,
                NameEn = component.NameEn,
                DisplayName = component.DisplayName,
                Number = component.Number,
                Tags = component.Tags,
                Model = component.Model,
                Type = component.Type,
                DerivedPropertiesJson = component.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(vessel),
                Unit = ObjectMapper.Map<Unit, UnitDto>(unit),
                Equipment = ObjectMapper.Map<Equipment, EquipmentDto>(equipment),
            };

            return componentDto;

        }

        [Authorize(PHMEEAdminPermissions.Components.Default)]
        public async Task<PagedResultDto<ComponentDto>> GetPagedComponentsAsync(ComponentListDto input)
        {

            var queryVessel = await vesselRepository.GetQueryableAsync();

            var query = queryVessel.SelectMany(vessel => vessel.Units.SelectMany(unit => unit.Equipments
                                                                     .SelectMany(equipment => equipment.Components
                                                                     .Select(component => new { Vessel = vessel, Unit = unit, Equipment = equipment, Component = component }))));

            query = query.WhereIf(input.EquipmentId != null, item => item.Equipment.Id == input.EquipmentId);

            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Component.Name.Contains(input.Name) || item.Component.NameEn.Contains(input.Name));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderBy(item => item.Component.EquipmentId).ThenBy(item => item.Component.Type).ThenBy(item => item.Component.Number);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var components = await AsyncExecuter.ToListAsync(query);

            var items = components.Select(e => new ComponentDto
            {
                Id = e.Component.Id,
                Name = e.Component.Name,
                NameEn = e.Component.NameEn,
                Number = e.Component.Number,
                Tags = e.Component.Tags,
                Model = e.Component.Model,
                DerivedPropertiesJson = e.Component.DerivedPropertiesJson,
                Vessel = ObjectMapper.Map<Vessel, VesselDto>(e.Vessel),
                VesselDisplayName = e.Vessel.DisplayName,
                Unit = ObjectMapper.Map<Unit, UnitDto>(e.Unit),
                UnitDisplayName = e.Unit.DisplayName,
                Equipment = ObjectMapper.Map<Equipment, EquipmentDto>(e.Equipment),
                EquipmentDisplayName = e.Equipment.DisplayName,
            }).ToList();

            return new PagedResultDto<ComponentDto>(totalCount, items);


        }

        public async Task<List<OperationOptionInt>> GetComponentTypes(Guid? id, Guid vesselId, Guid unitId, Guid equipmentId)
        {
            var vessel = await vesselRepository.PhmeeGetById(vesselId);

            var unit = vessel.GetUnit(unitId, L);

            var equipment = unit.GetEquipment(equipmentId, L);

            var localizedName = $"{PhmeeConst.BaseInfoTypeLocalizedComponent}";

            var options = vesselManager.GetComponentTypes().Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            var test = equipment.GetComponentTypeOptions();

            options = options.Where(item => equipment.GetComponentTypeOptions().Contains((ComponentEnum)item.Key)).ToList();

            return options;
        }

        #endregion

        #region 基础信息层级结构

        public async Task<VesselRelationDto> GetUnitRelation(Guid unitId)
        {
            var relation = await vesselManager.GetUnitRelation(unitId);
            var dto = new VesselRelationDto()
            {
                VesselId = relation.Item1?.Id,
                VesselName = relation.Item1?.DisplayName,
                UnitId = relation.Item2?.Id,
                UnitName = relation.Item2?.DisplayName,
            };
            return dto;
        }

        public async Task<VesselRelationDto> GetEquipmentRelation(Guid equipmentId)
        {
            var relation = await vesselManager.GetEquipmentRelation(equipmentId);
            var dto = new VesselRelationDto()
            {
                VesselId = relation.Item1?.Id,
                VesselName = relation.Item1?.DisplayName,
                UnitId = relation.Item2?.Id,
                UnitName = relation.Item2?.DisplayName,
                EquipmentId = relation.Item3?.Id,
                EquipmentName = relation.Item3?.DisplayName,
            };
            return dto;
        }

        public async Task<VesselRelationDto> GetComponentRelation(Guid componentId)
        {
            var relation = await vesselManager.GetComponentRelation(componentId);
            var dto = new VesselRelationDto()
            {
                VesselId = relation.Item1?.Id,
                VesselName = relation.Item1?.DisplayName,
                UnitId = relation.Item2?.Id,
                UnitName = relation.Item2?.DisplayName,
                EquipmentId = relation.Item3?.Id,
                EquipmentName = relation.Item3?.DisplayName,
                ComponentId = relation.Item4?.Id,
                ComponentName = relation.Item4?.DisplayName,
            };
            return dto;
        }

        public async Task<List<VesselTree>> GetBaseInfoTree(bool includePoints)
        {
            var nodes = await vesselManager.GetBaseInfoTree(includePoints);
            return nodes;
        }

        public List<OperationOptionInt> GetBaseInfoTags(string ownerType)
        {
            var localizedName = $"BaseInfoTagEnum";

            var options = vesselManager.GetBaseInfoLevelTags(ownerType).Select(item => new OperationOptionInt(item.Key, L[$"{localizedName}:{item.Value?.ToString()}"])).ToList();

            return options;
        }

        public List<OperationOptionInt> GetBaseInfoNumbers()
        {
            Dictionary<int, string> dict = new Dictionary<int, string>();

            for (int i = 1; i <= 20; i++)
            {
                dict.Add(i, $"{i}");
            }

            var options = dict.Select(item => new OperationOptionInt(item.Key, item.Value)).ToList();

            return options;
        }

        #endregion
    }
}
